package com.jweb.framework.core.config;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import com.jweb.framework.core.service.DefaultServiceHolder;
import com.jweb.framework.core.service.ServiceHolder;


public class TopServiceParser extends AbstractSingleBeanDefinitionParser {
	
	protected Class getBeanClass(Element ele){
		return ServiceFactoryBean.class ;
	}
	
	public static class ServiceFactoryBean implements FactoryBean<ServiceHolder>{
		
		private String name ;
		private Class<?>[] types ;
		private Object service ;
		
		public ServiceFactoryBean(String name , Class<?>[] types , Object service){
			this.name = name ;
			this.types = types ;
			this.service = service ;
		}
		
		public ServiceHolder getObject() throws Exception {
			
			return new DefaultServiceHolder(this.name , this.types , this.service);
			
		}
		
		public Class<?> getObjectType(){
			return ServiceHolder.class ;
		}
		
		public boolean isSingleton(){
			return true ;
		}
		
	}
	
	protected boolean shouldGenerateIdAsFallback(){
		return true ;
	}
	
	protected void doParse(Element ele , ParserContext parserContext , BeanDefinitionBuilder beanDefinitionBuilder){
		
		String name = ele.getAttribute("name");
		if(!StringUtils.hasText(name)){
			name = null ;
		}
		else {
			ele.removeAttribute("name");
		}
		
		beanDefinitionBuilder.addConstructorArgValue(name);
		
		String type = ele.getAttribute("type");
		if(!StringUtils.hasText(type) && name==null){
			parserContext.getReaderContext().error("must defined 'type' or 'name' attribute for service", ele);
		}
		beanDefinitionBuilder.addConstructorArgValue(type);
		
		String ref = ele.getAttribute("ref");
		if(StringUtils.hasText(ref)){
			beanDefinitionBuilder.addConstructorArgReference(ref);
		}
		else {
			BeanDefinitionHolder bHolder = parserContext.getDelegate().parseBeanDefinitionElement(ele , beanDefinitionBuilder.getRawBeanDefinition());
			if(bHolder != null){
				bHolder = parserContext.getDelegate().decorateBeanDefinitionIfRequired(ele , bHolder , beanDefinitionBuilder.getRawBeanDefinition());
			}
			else {
				parserContext.getReaderContext().error("cannot build bean", ele);
			}
			beanDefinitionBuilder.addConstructorArgValue(bHolder);
		}
	}
}
